home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-01-30 | 10.3 KB | 387 lines | [TEXT/R*ch] |
- Calling PowerPC Code
- From 68K Code
- There is a lot of information out there about calling 68K code from PowerPC
- code, but there is very little about calling PowerPC code from 68K code.
- Here is a nice method for calling PowerPC code from 68K code. I am using
- CodeWarrior 7. This is a bit lengthy so hang in there:
- There are three steps required to get things up and running. Let’s look at a
- sample scenario:
- You have a 68K application that you just can’t convert to PowerPC code (I don’t
- know why you can’t convert it, but just bear with me), but you can take some of
- the time-critical code and convert it to a PowerPC shared library and call it
- from the 68K code.
- Suppose you have two functions that perform data compression:
-
- long CompressData( unsigned char *inBuffer,
- unsigned char *outBuffer,
- unsigned long inBufferSize );
-
- long UncompressData( unsigned char *inBuffer,
- unsigned char *outBuffer,
- unsigned long inBufferSize );
-
- Step 1 – Create a PPC shared library containing your functions.
- We are going to export these functions using the #pragma export directive.
- This is set in the PPC Prefs area of Codewarrior preferences.
-
- “the shared library”
- // Prototypes
-
- #pragma export on
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- long CompressData( unsigned char *inBuffer,
- unsigned char *outBuffer,
- unsigned long inBufferSize );
-
- long UncompressData( unsigned char *inBuffer,
- unsigned char *outBuffer,
- unsigned long inBufferSize );
-
- #ifdef __cplusplus
- }
- #endif
-
- #pragma export off
- // CompressData
-
- long CompressData( unsigned char *inBuffer, unsigned char
- *outBuffer, unsigned long inBufferSize )
- {
- ... compress data code
- }
-
- // UncompressData
-
- long UncompressData( unsigned char *inBuffer, unsigned char
- *outBuffer, unsigned long inBufferSize )
- {
- ... uncompress data code
- }
- Set the project type to a shared library and build the project. We now have a
- PowerPC shared library that we will use in Step 2.
-
- Step 2 – Create a resource-based PEF Fragment that references our shared
- library.
- We create a header file that defines some mixed mode information.
-
- “the header file”
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- typedef long (*CompressDataProcPtr)( unsigned char *inBuffer,
- unsigned char *outBuffer, unsigned long inBufferSize );
- typedef long (*UncompressDataProcPtr)( unsigned char *inBuffer,
- unsigned char *outBuffer, unsigned long inBufferSize);
-
- #if GENERATINGCFM || USESROUTINEDESCRIPTORS
-
- typedef UniversalProcPtr CompressDataUPP;
- typedef UniversalProcPtr UncompressDataUPP;
-
- enum {
- uppCompressDataProcInfo = kCStackBased
- | RESULT_SIZE( SIZE_CODE( sizeof( long ) ) )
- | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(
- sizeof( unsigned
- char *) ) )
- | STACK_ROUTINE_PARAMETER( 2, SIZE_CODE(
- sizeof( unsigned
- char *) ) ) | STACK_ROUTINE_PARAMETER( 3, SIZE_CODE(
- sizeof( long ) ) )
- };
-
- enum {
- uppUncompressDataProcInfo = kCStackBased
- | RESULT_SIZE( SIZE_CODE( sizeof( long ) ) )
- | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(
- sizeof( unsigned
- char *) ) )
- | STACK_ROUTINE_PARAMETER( 2, SIZE_CODE(
- sizeof( unsigned
- char *) ) )
- | STACK_ROUTINE_PARAMETER( 3, SIZE_CODE(
- sizeof( long ) ) )
- };
-
- #else
-
-
- typedef CompressDataProcPtr CompressDataUPP;
- typedef UncompressDataProcPtr UncompressDataUPP;
- #endif
-
- //============================================================
- // Extern Globals
- //
-
- #ifndef powerc
-
- extern CompressDataUPP myCompressDataUPP;
- extern UncompressDataUPP myUncompressDataUPP;
-
- #endif
-
- //============================================================
- // Macros
- //
-
- #if GENERATINGPOWERPC || defined(powerc) || defined (__powerc)
-
- #define myCompressData( a, b, c ) CompressData( a, b, c )
- #define myUncompressData( a, b, c ) UncompressData( a, b, c )
-
- #else
-
- #define myCompressData( a, b, c ) \
- (*(CompressDataUPP)myCompressDataUPP( a, b, c )
- #define myUncompressData( a, b, c ) \
- (*(CompressDataUPP)myUncompressDataUPP( a, b, c )
-
- #endif
-
- //============================================================
- // Prototypes
- //
-
- long CompressData( unsigned char *inBuffer, unsigned char
- *outBuffer, unsigned long inBufferSize );
- long UncompressData( unsigned char *inBuffer, unsigned char
- *outBuffer, unsigned long inBufferSize );
-
- #ifdef __cplusplus
- }
- #endif
-
- Now we define the source file:
-
- “the source file”
- #include "the header file"
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- #if GENERATINGPOWERPC || defined(powerc) || defined (__powerc)
- #pragma options align=mac68k
- #endif
-
- #ifdef __CFM68K__
- #pragma lib_export on
- #endif
-
- RoutineDescriptor CompressDataRD =
- BUILD_ROUTINE_DESCRIPTOR( uppCompressDataProcInfo,
- CompressData );
-
- RoutineDescriptor UncompressDataRD =
- BUILD_ROUTINE_DESCRIPTOR( uppUncompressDataProcInfo,
- UncompressData );
-
-
- #ifdef __CFM68K__
- #pragma lib_export off
- #endif
-
- #if GENERATINGPOWERPC || defined(powerc) || defined (__powerc)
- #pragma options align=reset
- #endif
-
- #ifdef __cplusplus
- }
- #endif
-
- Add the shared library we built in Step 1 to this project.
- Set the project type to shared library and build the project. We now have a
- PowerPC shared library that we want to convert to a resource. (Note: we don’t
- export this as a PowerPC code resource with no header, since we would get link
- errors for an undefined main entry.)
- Open the file up in a resource editor and create a new resource (I use a type
- of 'PEF ', but any will do). Move the PEF code from the data fork into this
- resource. (If your resource editor will not do this, then it is a simple
- matter of creating a small application that will do this for you; this
- excercise is left for the reader.)
- We now have a resource file that we will add to our 68K project.
-
- Step 3 – Add 68K support code to your project
- Your 68K project needs to have a bit of support code to get the code resource
- and load it in as a code fragment. Add to your code:
-
- #include "the header file"
-
- We need to declare some globals for the universal procs that will store the
- address of the routine descriptors. Add to your code:
-
- #ifndef powerc
- CompressDataUPP myCompressDataUPP;
- UncompressDataUPP myUncompressDataUPP;
- #endif
-
- The following function takes care of checking for the existence of the CFM and
- Mixed Mode managers. We pass it a pointer to a CFragConnectionID variable and a
- Handle variable, which we will use later on for clean up. Add to your code:
-
- #ifndef powerc
-
- // SetupPPCNativeCode
-
- OSErr SetupPPCNativeCode( CFragConnectionID *connID,
- Handle *PEFHandle,
- ResType codeFragmentType,
- short codeFragmentID )
- {
- OSErr theErr = noErr;
- long templong;
- Str255 failedFragName;
-
-
- // get PEF container resource from our resource fork
-
- *PEFHandle = ::Get1Resource( codeFragmentType, codeFragmentID );
- theErr = ::ResError();
-
- if( !(*PEFHandle) )
- {
- if( theErr )
- return( theErr );
- else
- return( ::MemError() );
- }
-
- // Check for Mixed Mode Manager and Code Fragment Manager (CFM)
-
- Boolean hasMixedMode = !Gestalt( gestaltMixedModeAttr,
- &templong );
- Boolean hasCFM = !Gestalt( gestaltCFMAttr, &templong );
-
- theErr = Gestalt( gestaltSysArchitecture, &templong );
- if( ( theErr ) ||
- ( templong == gestalt68k ) ||
- ( !hasCFM ) ||
- ( !hasMixedMode ) )
- {
- ::ReleaseResource( *PEFHandle );
- return( -1 );
- }
-
- DetachResource( *PEFHandle );
- MoveHHi( *PEFHandle );
- HLock( *PEFHandle );
-
- // Assume this is PowerPC code, so it must be “prepared”
-
- theErr = ::GetMemFragment( (Ptr)**PEFHandle, 0, 0,
- kNewCFragCopy, connID, 0, failedFragName );
- if( theErr )
- {
- DisposeHandle( *PEFHandle );
- return( theErr );
- }
-
- CFragSymbolClass myClass;
-
- if( !theErr )
- theErr = ::FindSymbol( *connID,
- (ConstStr255Param)"\pCompressDataRD",
- (Ptr*)&myCompressDataUPP,
- &myClass );
- if( !theErr )
- theErr = ::FindSymbol( *connID,
- (ConstStr255Param)"\pUncompressDataRD",
- (Ptr*)&myUncompressDataUPP,
- &myClass );
-
- if( theErr )
- {
- DisposeHandle( *PEFHandle );
- return( theErr );
- }
-
- return( noErr );
- }
-
- The following function takes the connection id and handle returned from
- SetupPPCNativeCode, frees the connection and disposes of the handle. Add to
- your code:
-
- // TearDownPPCNativeCode
-
- void TearDownPPCNativeCode( CFragConnectionID connID, Handle PEFHandle )
- {
- ::CloseConnection( &connID );
- if( PEFHandle )
- ::DisposeHandle( PEFHandle );
- }
-
- #endif
-
- Build your 68K project as you normally would and be sure to include the
- resource file we created in Step 2 and ensure the the shared library we created
- in Step 1 is either in the Extensions folder of the System Folder or in the
- same directory as the application.
- Here is what you would do the call the PowerPC code from 68K:
-
- long PowerPC_Compress( unsigned char *inBuffer, unsigned char
- *outBuffer, unsigned long inBufferSize )
- {
- #ifndef powerc
-
- // For efficiency you would probably put this call in initialization code.
- // sConnID and sPEFHandle are static globals.
-
- OSErr err = SetupPPCNativeCode( &sConnID, &sPEFHandle,
- 'PEF ', 128 );
- if( err )
- return( 0 ); // We couldn’t compress anything so return 0
- #endif
-
- long result = 0;
-
- result = myCompressData( inBuffer, outBuffer, inBufferSize );
-
- #ifndef powerc
-
- // For efficiency you would probably put this call in termination code.
-
- TearDownPPCNativeCode( sConnID, sPEFHandle );
- #endif
- }
-
- long PowerPC_Uncompress( unsigned char *inBuffer,
- unsigned char *outBuffer, unsigned long inBufferSize )
- {
- #ifndef powerc
-
- // For efficiency you would probably put this call in initialization code.
- // sConnID and sPEFHandle are static globals.
-
- OSErr err = SetupPPCNativeCode( &sConnID, &sPEFHandle,
- 'PEF ', 128 );
- if( err )
- return( 0 ); // We couldn’t compress anything so return 0
- #endif
-
- long result = 0;
-
- result = myUncompressData( inBuffer, outBuffer, inBufferSize );
-
- #ifndef powerc
-
- // For efficiency you would probably put this call in termination code.
-
- TearDownPPCNativeCode( sConnID, sPEFHandle );
- #endif
- }
-
-
- That’s all there is to it. Enjoy and happy coding.
- – Chris Rudolph
-
- [BuildRoutineDescriptor() doesn’t work right with CFM68k; use
- NewRoutineDescriptor() instead. BuildRoutineDescriptor() generates code so you
- need to call MakeDataExecutable() after it. – sgs]
-